From: Keir Fraser Date: Tue, 11 May 2010 10:21:27 +0000 (+0100) Subject: x86: Detect and handle unexpected platform-timer counter wrap. X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~12196 X-Git-Url: https://dgit.raspbian.org/%22http:/www.example.com/cgi/%22https:/%22bookmarks://%22/%22http:/www.example.com/cgi/%22https:/%22bookmarks:/%22?a=commitdiff_plain;h=1848a2d7adae4200442ffebff45371a3b3c94069;p=xen.git x86: Detect and handle unexpected platform-timer counter wrap. Signed-off-by: Keir Fraser --- diff --git a/xen/arch/x86/time.c b/xen/arch/x86/time.c index f467eecc5b..1ba23f9f46 100644 --- a/xen/arch/x86/time.c +++ b/xen/arch/x86/time.c @@ -571,26 +571,48 @@ static u64 plt_stamp64; /* 64-bit platform counter stamp */ static u64 plt_stamp; /* hardware-width platform counter stamp */ static struct timer plt_overflow_timer; +static s_time_t __read_platform_stime(u64 platform_time) +{ + u64 diff = platform_time - platform_timer_stamp; + ASSERT(spin_is_locked(&platform_timer_lock)); + return (stime_platform_stamp + scale_delta(diff, &plt_scale)); +} + static void plt_overflow(void *unused) { + int i; u64 count; + s_time_t now, plt_now, plt_wrap; spin_lock_irq(&platform_timer_lock); + count = plt_src.read_counter(); plt_stamp64 += (count - plt_stamp) & plt_mask; plt_stamp = count; + + now = NOW(); + plt_wrap = __read_platform_stime(plt_stamp64); + for ( i = 0; i < 10; i++ ) + { + plt_now = plt_wrap; + plt_wrap = __read_platform_stime(plt_stamp64 + plt_mask + 1); + if ( ABS(plt_wrap - now) > ABS(plt_now - now) ) + break; + plt_stamp64 += plt_mask + 1; + } + if ( i != 0 ) + { + static bool_t warned_once; + if ( !test_and_set_bool(warned_once) ) + printk("Platform timer appears to have unexpectedly wrapped " + "%u%s times.\n", i, (i == 10) ? " or more" : ""); + } + spin_unlock_irq(&platform_timer_lock); set_timer(&plt_overflow_timer, NOW() + plt_overflow_period); } -static s_time_t __read_platform_stime(u64 platform_time) -{ - u64 diff = platform_time - platform_timer_stamp; - ASSERT(spin_is_locked(&platform_timer_lock)); - return (stime_platform_stamp + scale_delta(diff, &plt_scale)); -} - static s_time_t read_platform_stime(void) { u64 count;